﻿/*
 * cumulantmgr.cpp
 *
 *  Created on: 2017年3月27日
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_SCADA DM_API_EXPORT

#include <dm/scada/cumulantmgr.hpp>

#include <dm/scada/scadainfo.hpp>
#include <dm/scada/devicemgr.hpp>
#include <dm/os/log/logger.hpp>
#include <dm/datetime.hpp>

namespace dm{
namespace scada{

static const char* logModule = "CCumulantMgr.scada.dm";

/**
 * 构造函数
 * @param scada
 */
CCumulantMgr::CCumulantMgr( CScada& scada ):CScada(scada),
		m_cfg(scada.cumulantInfos(),scada.info()->cumulantCount()){
}

/**
 * 全局唯一实例
 * @return
 */
CCumulantMgr& CCumulantMgr::ins(){
	static CCumulantMgr i(CScada::ins());
	return i;
}

/**
 * 设置描述
 * @param idx
 * @param str
 * @return
 */
bool CCumulantMgr::setDesc( const index_t& idx,const char* str ){
	SCumulantInfo* p = m_cfg.at(idx);
	if( p ){
		p->desc = str;
		return true;
	}else
		return false;
}

/**
 * 设置变化限值
 * @param idx
 * @param delta
 * @return
 */
bool CCumulantMgr::setDelta( const index_t& idx,SCumulantInfo::delta_t delta ){
	SCumulantInfo* p = m_cfg.at(idx);
	if( p ){
		p->delta = delta;
		return true;
	}else
		return false;
}

/**
 * 设置满码值
 * @param idx
 * @param code
 * @return
 */
bool CCumulantMgr::setMaxCode( const index_t& idx,SCumulantInfo::code_t code ){
	SCumulantInfo* p = m_cfg.at(idx);
	if( p ){
		p->maxCode = code;
		return true;
	}else
		return false;
}

/**
 * 设置系数
 * @param idx
 * @param coef
 * @return
 */
bool CCumulantMgr::setCoef( const index_t& idx,SCumulantInfo::coef_t coef ){
	SCumulantInfo* p = m_cfg.at(idx);
	if( p ){
		p->coef = coef;
		return true;
	}else
		return false;
}

/**
 * 设置存盘标志
 * @param idx
 * @param s
 * @return
 */
bool CCumulantMgr::setFlagSave( const index_t& idx,bool s ){
	SCumulantInfo* p = m_cfg.at(idx);
	if( p ){
		p->setFlagSave(s);
		return true;
	}else
		return false;
}

/**
 * 设置产生时标数据标志
 * @param idx
 * @param s
 * @return
 */
bool CCumulantMgr::setFlagGenTimed( const index_t& idx,bool s ){
	SCumulantInfo* p = m_cfg.at(idx);
	if( p ){
		p->setFlagGenTimed(s);
		return true;
	}else
		return false;
}

/**
 * 设置上报时标数据标志
 * @param idx
 * @param s
 * @return
 */
bool CCumulantMgr::setFlagReportTimed( const index_t& idx,bool s ){
	SCumulantInfo* p = m_cfg.at(idx);
	if( p ){
		p->setFlagReportTimed(s);
		return true;
	}else
		return false;
}

/**
 * 根据实时指针获取累计量索引号
 * @param value
 * @return
 */
index_t CCumulantMgr::indexOfRt( const rt_t* value )const{
	if( value<cumulants() || value>cumulants()+size() )
		return Idx_Inv;
	return value - cumulants();
}

/**
 * 根据实时指针获取累计量索引号
 * @param value
 * @return
 */
index_t CCumulantMgr::indexOfRt( const volatile rt_t* value )const{
	if( value<cumulants() || value>cumulants()+size() )
		return Idx_Inv;
	return value - cumulants();
}

/**
 * 获取累计量所属设备的索引
 * @param idx 累计量索引号
 * @return 设备索引
 */
index_t CCumulantMgr::deviceIndex( const index_t& idx )const{
	if( idx<0 || idx>=size() )
		return Idx_Inv;
	CDeviceMgr& d = CDeviceMgr::ins();

	for( index_t i=0;i<d.size();++i ){
		if( d.info(i)->posOfCumulant<=idx &&
				(d.info(i)->posOfCumulant+d.info(i)->sizeOfCumulant)>idx )
			return i;
	}

	return Idx_Inv;
}

const char* CCumulantMgr::deviceDesc( const index_t& idx )const{
	if( idx<0 || idx>=size() )
		return NULL;
	CDeviceMgr& d = CDeviceMgr::ins();

	for( index_t i=0;i<d.size();++i ){
		if( d.info(i)->posOfCumulant<=idx &&
				(d.info(i)->posOfCumulant+d.info(i)->sizeOfCumulant)>idx )
			return d.info(i)->desc.c_str();
	}

	return NULL;
}

CCumulant::value_t CCumulantMgr::calcValue( const index_t& idx,const CCumulant::raw_t& raw )const{
	const SCumulantInfo* p = info(idx);
	if( p==NULL ){
		log().warnning(THISMODULE "累计量索引(%d)错误(%d)",idx,size());
		return 0;
	}

	CCumulant::value_t v = CCumulant::value_t(raw);
	v *= p->coef;
	return v;
}

/**
 * 更新累计量实时数据
 * @param idx 累计量索引
 * @param raw 累计量原始值
 * @param ds 数据源
 * @param ts 时标
 * @return 是否更新成功
 */
bool CCumulantMgr::update( const index_t& idx,const CCumulant::raw_t& raw,const EDataSource& ds,const dm::CTimeStamp& ts ){
	const SCumulantInfo* p = info(idx);
	if( p==NULL ){
		log().warnning(THISMODULE "累计量索引(%d)错误(%d)",idx,size());
		return false;
	}

	cumulant_t* pv = cumulants()+idx;

	const CCumulant::raw_t ro = pv->getValue().getRaw();
	if( raw==ro )
		return false;

	CCumulant::value_t v = CCumulant::value_t(raw);
	v *= p->coef;

	if( (p->delta) > 0 ){
		if( v>pv->getValue().getValue() ){
			if( v - pv->getValue().getValue() < p->delta )
				return false;
		}else{
			if( pv->getValue().getValue() - v < p->delta )
				return false;
		}
	}

	pv->update( CCumulant(v,raw),ds,ts);

	if( p->isFlagGenTimed() )
		CTimedCumulantMgr::ins().push( CTimedCumulant(idx,raw,ts));

	return true;
}

bool CCumulantMgr::set( const index_t& idx,const CCumulant::raw_t& raw,const EDataSource& ds,const dm::CTimeStamp& ts ){
	const SCumulantInfo* p = info(idx);
	if( p==NULL ){
		log().warnning(THISMODULE "累计量索引(%d)错误(%d)",idx,size());
		return false;
	}

	cumulant_t* pv = cumulants()+idx;

	CCumulant::value_t v = CCumulant::value_t(raw);
	v *= p->coef;

	pv->update( CCumulant(v,raw),ds,ts);

	return true;
}

bool CCumulantMgr::gen( const index_t& idx,const CCumulant::raw_t& raw,const dm::CTimeStamp& ts ){
	const SCumulantInfo* p = info(idx);
	if( p==NULL ){
		log().warnning(THISMODULE "累计量索引(%d)错误(%d)",idx,size());
		return false;
	}

	CCumulant::value_t v = CCumulant::value_t(raw);
	v *= p->coef;

	CTimedCumulantMgr::ins().push( CTimedCumulant(idx,raw,ts));

	return true;
}

/**
 * 格式化输出累计量信息
 * @param idx 累计量索引号
 * @param ostr 输出流
 */
void CCumulantMgr::printInfo( const index_t& idx,std::ostream& ostr )const{
	const SCumulantInfo* p = info(idx);
	if( p ){
		ostr <<"ID:"<<p->id
				<<" 名字:"<<p->name.c_str()
				<<" 描述:"<<p->desc.c_str()
				<<" 满码:"<<p->maxCode
				<<" 最小变化值:"<<p->delta
				<<" 系数:"<<p->coef
				<<" 存盘:";
		if( p->isFlagSave() )
			ostr <<"允许";
		else
			ostr <<"禁止";

		ostr <<" 产生时标数据:";
		if( p->isFlagGenTimed() )
			ostr <<"是";
		else
			ostr <<"否";

		ostr <<" 上报时标数据:";
		if( p->isFlagReportTimed() )
			ostr <<"是";
		else
			ostr <<"否";
	}else{
		ostr <<"无效索引("<<idx<<')';
	}
}

void CCumulantMgr::printInfoValue( const index_t& idx,std::ostream& ostr ){
	const SCumulantInfo* p = info(idx);
	if( p ){
		rt_t* pv = rt(idx);
		ostr <<"ID:"<<p->id
				<<" 名字:"<<p->name.c_str()
				<<" 描述:"<<p->desc.c_str()
				<<" 值:"<<pv->getValue().getValue()
				<<" 数据方式:"<<pv->getDataSource()
				<<" 码值:"<<pv->getValue().getRaw()
				<<" 时标:"<< dm::CDateTime(pv->getTimeStamp()).toString().c_str();
	}else{
		ostr <<"无效索引号"<<idx;
	}
}
}
}


